package com.wmyg.tracker.sdk;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.yaml.snakeyaml.Yaml;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;


public class SmartManager {

    @Value("${server.port}")
    private static String serverPort;

    private OrgManager orgManager;

    private FabricManager fabricManager;

    private Logger logger = LogManager.getLogger(SmartManager.class);

    private String orgName;




    //2018-9-5
    private String userName;
    private String codePath;
    private String channelName;


    public SmartManager(String orgName, String userName, String codePath, String channelName, boolean isToInstall) throws Exception {
        this.orgName = orgName;
        if (isToInstall) {
            initToInstall(orgName, userName, codePath, channelName);
        } else {
            initToUse(orgName, userName, codePath, channelName);
            this.userName = userName;
            this.codePath = codePath;
            this.channelName = channelName;
        }
//        initToUse(orgName, userName, codePath, channelId);

    }

    private void initToInstall(String orgName, String userName, String codePath, String channelName) throws FileNotFoundException {
        orgManager = new OrgManager();
        Yaml yaml = new Yaml();
        ChaincodeConfig chaincodeConfig = (ChaincodeConfig) yaml.load(new FileInputStream(new File("code/src/" + codePath + "config/chaincodeconfig.yaml")));
        int id = orgName.hashCode();
        orgManager.initOrg(id, new File("cert/" + orgName + ".yaml"), userName, true)
                .setChannel(channelName)
                .setChainCode(chaincodeConfig.getCodeName(), codePath,
                        chaincodeConfig.getCodeVersion(), "code/", 10000, 10)
                .setBlockListener(map -> {
                    logger.debug(map.get("code"));
                    logger.debug(map.get("data"));
                }).initNetworkSetting();
    }

    private void initToUse(String orgName, String userName, String codePath, String channelName) throws FileNotFoundException {
        orgManager = new OrgManager();
        Yaml yaml = new Yaml();
        ChaincodeConfig chaincodeConfig = (ChaincodeConfig) yaml.load(new FileInputStream(new File("code/src/" + codePath + "config/chaincodeconfig.yaml")));
        int id = orgName.hashCode();
        orgManager.initOrg(id, new File("cert/" + orgName + ".yaml"), userName, true)
                .setChannel(id,channelName)
                .setChainCode(id,chaincodeConfig.getCodeName(), codePath,
                        chaincodeConfig.getCodeVersion(), 10000, 10)//120000
//                .setBlockListener(map -> {
//                    logger.debug(map.get("code"));
//                    logger.debug(map.get("data"));
//                })
                .initNetworkSetting(id);
    }


    @Deprecated
    public FabricResult invoke(String fcn, String[] args) {

          return fabricManager.invoke(fcn, args);
//        FabricResult fabricResult = new FabricResult();
////        initToUse(orgName, userName, codePath, channelId);
////        fabricManager = orgManager.useCommonly(orgName.hashCode());
//        //System.out.println("ThreadID:" + Thread.currentThread().getId() + " Hash:" + fabricManager.hashCode() + " Smart:" + this.hashCode());
////        StringBuilder sb = new StringBuilder();
////        for (String item : args) {
////            sb.append(item).append(';');
////        }
////        System.out.println("invok fun:" + fcn + "  args:" + sb.toString());
//        try {
//            Map<String, String> map = fabricManager.invoke(fcn, args);
////        System.out.println(map);
//            if ("error".equals(map.get("code"))) {
////                fabricManager.abandon();
////                throw new FabricException(map.get("cause"));
//                fabricResult.setCode(4);
//                fabricResult.setData(map.get("data"));
//                fabricResult.setDescription(map.get("cause"));
//                return fabricResult;
//            }
////        fabricManager.abandon();
////            return map;
//            fabricResult.setCode(0);
//            fabricResult.setDescription("success");
//            fabricResult.setData(map.get("data"));
//        } catch (InvalidArgumentException e) {
//            /*
//            * 无效参数错误
//            * 1. 提案请求关键字为空
//            * 2. 提案请求内容为空
//            * 3. 提案请求方法名为空
//            * 4. 提案请求链码ID为空
//            * 5. 提案请求已被提交
//            * 6. 用户上下文错误包括整个用户上下文、用户名、mspID、是否登记等
//            * 7. 提案请求链码类型错误
//            * 8. 提案响应集各种错误
//            * 9. 通道未初始化或者已关闭
//            * 10. 未设置目标节点
//             */
//            e.printStackTrace();
//            fabricResult.setCode(1);
//            fabricResult.setDescription(e.getMessage());
////            logger.info("Find the Channel is shutdown, ready to restart program for the port " + serverPort);
////            try {
////                Runtime.getRuntime().exec("nohup /mnt/fabricuploader/fabricuploader.sh " + serverPort + " &");
////            } catch (IOException e1) {
////                e1.printStackTrace();
////            }
////            fabricManager = orgManager.useAgain(orgName.hashCode());
////            throw e;
//        } catch (ProposalException e) {
//            /*
//            * 提案异常
//            * 1. 提案无法进行签名
//            * 2. 提案请求建立异常
//             */
//            e.printStackTrace();
//            fabricResult.setCode(2);
//            fabricResult.setDescription(e.getMessage());
//        } catch (TimeoutException e) {
//            //各种超时，包括peer请求超时，orderer请求超时
//            e.printStackTrace();
//            fabricResult.setCode(3);
//            fabricResult.setDescription(e.getMessage());
////        } catch (FabricException e) {
////            e.printStackTrace();
//        } catch (ExecutionException e) {
//            e.printStackTrace();
//            fabricResult.setCode(5);
//            fabricResult.setDescription(e.getMessage());
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//            fabricResult.setCode(6);
//            fabricResult.setDescription(e.getMessage());
//        } catch (IOException e) {
//            //字符集转换错误
//            e.printStackTrace();
//            fabricResult.setCode(7);
//            fabricResult.setDescription(e.getMessage());
//        } catch (TransactionException e) {
//            e.printStackTrace();
//            fabricResult.setCode(7);
//            fabricResult.setDescription(e.getMessage());
//        }
//        return fabricResult;
    }

//    public Map<String, String> query(String fcn, String[] keys) throws Throwable {
////        initToUse(orgName, userName, codePath, channelId);
////        FabricManager fabricManager = orgManager.useCommonly(orgName.hashCode());
//        Map<String, String> map = fabricManager.query(fcn, keys);
////        fabricManager.abandon();
//        return map;
//    }

    @Deprecated
    public FabricResult query(String fcn, String[] keys) throws Throwable {
//        initToUse(orgName, userName, codePath, channelId);
//        FabricManager fabricManager = orgManager.useCommonly(orgName.hashCode());
        FabricResult ret= fabricManager.query(fcn, keys);
//        fabricManager.abandon();
        return ret;
    }

//    public IntermediateChannel getChannel(String alias){
////      IntermediateChannel channel = new IntermediateChannel();
////      channel.setChannelName(channelName);
////      orgMap.get(id).setChannel(channel);
//        fabricManager = orgManager.createByOrg(orgName.hashCode());
//        return fabricManager.getChannel(alias);
//    }

   synchronized  public FabricManager createFabric(String alias){
//      IntermediateChannel channel = new IntermediateChannel();
//      channel.setChannelName(channelName);
//      orgMap.get(id).setChannel(channel);
        try {
            FabricManager fabricManager = orgManager.createByOrg(orgName.hashCode());
            if(alias == null){
                //need a unique name
            }
            fabricManager.createChannel(alias);
            return fabricManager;
        }
        catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    // ?????
    public void firstInstall(String[] args) throws Throwable {
        fabricManager = orgManager.use(orgName.hashCode());
        fabricManager.install();
        fabricManager.instantiate(args);
        fabricManager.abandon();
    }
    // ?????
    public void install(String[] args) throws Throwable {
        fabricManager = orgManager.use(orgName.hashCode());
        fabricManager.install();
        fabricManager.upgrade(args);
        fabricManager.abandon();
    }

    public int getInvokeWaitTime() {
        return fabricManager.getInvokeWaitTime();
    }

    public void setInvokeWaitTime(int invokeWaitTime) {
        fabricManager.setInvokeWaitTime(invokeWaitTime);
    }

}
